Spring Data JPA分页和排序

Sort类和Pageable类介绍

PagingAndSortingRepository是Spring Data JPA实现分页的接口:

1
2
3
4
5
6
7
public interface PagingAndSortingRepository<T, ID extends Serializable> 
extends CrudRepository<T, ID> {

Iterable<T> findAll(Sort var1);

Page<T> findAll(Pageable var1);
}

第二个findAll方法就是实现分页的方法,参数是Pageable类型,同参数传入当前的分页对象(如:第几页,每页多少条记录,排序信息等),查询完成之后会返回一个Page的对象。Page对象中就存储了所有的分页信息。

Pageable接口的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Pageable {
int getPageNumber();

int getPageSize();

int getOffset();

Sort getSort();

Pageable next();

Pageable previousOrFirst();

Pageable first();

boolean hasPrevious();
}

它的实现类有三个,主要用到的是PageRequest,PageRequest有三个构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 这个构造出来的分页对象不具备排序功能
* 特别注意页数是从0开始的,而不是1
* @param page zero-based page index.
* @param size the size of the page to be returned.
*/
public PageRequest(int page, int size) {
this(page, size, null);
}
/**
* Direction和properties用来做排序操作
*/
public PageRequest(int page, int size, Direction direction, String... properties) {
this(page, size, new Sort(direction, properties));
}
/**
* 自定义一个排序的操作
*/
public PageRequest(int page, int size, Sort sort) {
super(page, size);
this.sort = sort;
}

Sort是一排序类,首先有一个内部枚举对象Direction,Direction中有两个值ASC和DESC分别用来确定升序还是降序,Sort还有一个内部类OrderOrder有有两个比较重要的属性Sort.Directionproperty,第一个用来确定排序的方向,第二个就是排序的属性。

Sort主要用到如下两个构造函数:

1
2
3
4
5
//可以输入多个Sort.Order对象,在进行多个值排序时有用
public Sort(Sort.Order... orders)

//当排序方向固定时,使用这个比较方便,第一个参数是排序方向,第二个是排序的字段,
public Sort(Sort.Direction direction, String... properties)

分页排序查询

e.g. 每页5条,取第1页,按id降序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void testPageAndSort(){
Sort sort = new Sort(Sort.Direction.DESC, "id");

//页数index是从0开始的,而不是1
Pageable pageable = new PageRequest(0, 5, sort);

Page<User> users = repository.findAll(pageable);

System.out.println("总页数:" + users.getTotalPages());
System.out.println("总记录数:" + users.getTotalElements());
System.out.println("当前第几页:" + users.getNumber()+1);
System.out.println("当前页面的集合:" + users.getContent());
System.out.println("当前页面的记录数:" + users.getNumberOfElements());
}

使用JpaSpecificationExecutor接口实现条件查询

Criteria查询是一种以更加面向对象的方式查询数据库的方法,是JPA 2.0 引入的关键特性之一。

e.g. 每页5条,取第1页,按id降序,名字含有D 且 年龄大于18

1
2
public interface UserRepository extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User>{ 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Test
public void testSpecificationExecutor(){
Sort sort = new Sort(Sort.Direction.DESC, "id");

//页数index是从0开始的,而不是1
Pageable pageable = new PageRequest(0, 5, sort);

/**
* root:简单看成就是要查询的对象类型(User)
* query:添加查询条件
* cb:构建Predicate
*/
Specification<User> specification = new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root,
CriteriaQuery<?> query,
CriteriaBuilder cb) {
//root.get("name")表示获取name这个字段名称,
//like表示执行like查询, %D% 表示值,注意要带上%
Predicate p1 = cb.like(root.get("name"), "%D%");
Predicate p2 = cb.greaterThan(root.get("age"),20);
return cb.and(p1, p2);
}
};

Page<User> users = repository.findAll(specification, pageable);

System.out.println("总页数:" + users.getTotalPages());
System.out.println("总记录数:" + users.getTotalElements());
System.out.println("当前第几页:" + users.getNumber()+1);
System.out.println("当前页面的集合:" + users.getContent());
System.out.println("当前页面的记录数:" + users.getNumberOfElements());
}

参考链接

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.core-concepts